package com.admins.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.commons.enums.ResponseCodeEnum;
import com.commons.utils.Constance;
import com.commons.utils.JsonUtil;
import com.commons.utils.JwtUtil;
import com.commons.utils.ResponseResult;
import com.github.pagehelper.PageInfo;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.admins.dto.AdminLoginDto;
import com.admins.entity.Users;
import com.admins.service.AdminService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author mis_wu
 * @date 2021/11/28 21:52
 */
@RestController
@RequestMapping("/admins-services")
@SuppressWarnings("unchecked")
//作用在模块API类上，对API模块进行说明
@Api(tags = "Admins-Service-Api 管理员微服务接口")
//nacos修改文件自动刷新(放在需要自动刷新的类上)
@RefreshScope
public class AdminController {

    /**
     * 限流资源名（规则名称）
     */
    private static final String RESOURCE_KEY = "adminFlowRule";
    @Resource
    private AdminService adminService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    private static final Logger log= LoggerFactory.getLogger(AdminController.class);

    @ApiOperation("管理员登录登录")
    @ApiOperationSupport(author = "mis_xxx")
    @PostMapping("/adminlogin")
    public ResponseResult login(@ApiParam("登录信息") @RequestBody AdminLoginDto login){
        //引用限流规则 try-catch方式(不推荐),推荐注解形式限流,如下
        Entry entry = null;
        try {
            entry = SphU.entry(RESOURCE_KEY);
        } catch (Exception e) {
            //限流的话就会进入到catch
            return new ResponseResult(201,"当前访问人数过多,请稍后再试!");
        }finally {
            //关闭
            //SphU.entry(xxx)需要与entry.exit()成对出现,否则会导致调用链记录异常;
            if (entry != null){
                entry.exit();
            }
        }
        AdminLoginDto adminLoginDto = adminService.adminLogin(login.getLoginId());
        if (!ObjectUtils.isEmpty(adminLoginDto)){
            //jwt验证 token
            boolean checkPwd = BCrypt.checkpw(adminLoginDto.getLoginPwd(), login.getLoginPwd());
            if (checkPwd){
                Map<String, String> info = new HashMap<>(8);
                info.put("username", adminLoginDto.getLoginId());
                String token = JwtUtil.createJWT(UUID.randomUUID().toString(), login.getLoginId(), 3600L*1000);
                info.put("token",token);
                log.info("鉴权信息:{}",token);
                redisTemplate.opsForValue().set("jwt",token,60,TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(Constance.TOKEN_KEY+token, adminLoginDto,60,TimeUnit.MINUTES);
                amqpTemplate.convertAndSend("admins-mq",adminLoginDto);
                String data = JsonUtil.jsonUtil(info);
                return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),ResponseCodeEnum.SUCCESS.getMsg(),data);
            }
            return new ResponseResult(ResponseCodeEnum.FAIL.getCode(),ResponseCodeEnum.FAIL.getMsg());


//            if (adminLoginDto.getLoginPwd().equals(login.getLoginPwd())){
//                String token=session.getId();
//                //给当前管理员随机分配头像
//                String avatarPath=AvatarRandom.getAvatarPath();
//                login.setAvatar(avatarPath);
//                adminService.savePic(login);
//                //redisTemplate.setKeySerializer(new StringRedisSerializer());
//                redisTemplate.opsForValue().set(Constance.TOKEN_KEY+token, adminLoginDto,60,TimeUnit.MINUTES);
//                //redisTemplate.expire(token,60, TimeUnit.MINUTES);
//                //向rabbitmq发送消息(users消费该消息)
//                amqpTemplate.convertAndSend("admins-mq",adminLoginDto);
//                return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),ResponseCodeEnum.SUCCESS.getMsg(),new LoginAdminInfoVo(avatarPath,token));
//            }else {
//                return new ResponseResult(ResponseCodeEnum.PASSWORD_ERROR.getCode(),ResponseCodeEnum.PASSWORD_ERROR.getMsg());
//            }
        }else {
            return new ResponseResult(ResponseCodeEnum.USERNAME_NOT_NULL.getCode(),ResponseCodeEnum.USERNAME_NOT_NULL.getMsg());
        }
    }

    @ApiOperation("分页查询用户列表")
    @GetMapping("/userlist/{page}/{size}")
    public ResponseResult queryAllUsersList(@PathVariable int page,@PathVariable int size){
        Map map=new HashMap();
        PageInfo<Users> users = adminService.queryAllUsers(page,size);
        if (users!=null){
            map.put("userlist",users.getList());
            map.put("totals",users.getTotal());
        }else {
            map.put("userlist",null);
        }
        return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode(),ResponseCodeEnum.SUCCESS.getMsg(),map);
    }

    @ApiOperation("修改用户信息")
    @PostMapping("/updateUserInfo")
    public ResponseResult updateUserInfo(@RequestBody Users users){
        log.info("users {}",users);
        int res = adminService.updateUserInfo(users);
        if (res!=1){
            return new ResponseResult(ResponseCodeEnum.PARAMETERERROR.getCode());
        }
        return new ResponseResult(ResponseCodeEnum.SUCCESS.getCode());
    }

    @GetMapping("/create")
    @ApiOperation("/create 设置header")
    public ResponseEntity<Void> demo2(){
        //return new ResponseEntity<Void>(HttpStatus.CREATED);
        MultiValueMap headers=new HttpHeaders();
        headers.set("token","mis_wu");//设置header
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }

    /**
     * 手动创建
     * 创建限流规则
     * @return
     */
    @GetMapping("/initFlowQpsRule")
    public String initFlowQpsRule(){
        ArrayList<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setRefResource(RESOURCE_KEY);
        //QPS控制在 1 以内
        rule.setCount(1);
        //QPS限流
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setLimitApp("default");
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        log.info(">>>>"+Thread.currentThread().getName()+">>>>");
        return "...限流配置初始化成功...";
    }

    /**
     * 推荐使用注解形式限流
     * value 资源名称
     * blockHandler 限流/熔断出现异常后执行的方法
     * fallback 服务降级执行的本地方法
     * @return
     */
    @SentinelResource(value = RESOURCE_KEY, blockHandler = "flowRuleFailException")
    @GetMapping("/annotationsFlowRule")
    public String annotationsFlowRule(){
        return "annotationsFlowRule-success";
    }

    /**
     * 被限流后返回的提示
     * @param e
     * @return
     */
    public String flowRuleFailException(BlockException e){
        e.printStackTrace();
        return "请求次数过快,请稍后再试!";
    }

    /**
     * 动态创建sentinel
     * 注意:没有@SentinelResource注解情况下,默认的资源名称为接口名称(/flowRuleConsoleDynamic)
     * @return
     */
    @GetMapping("/flowRuleConsoleDynamic")
    @SentinelResource(value = "flowRuleConsoleDynamic",blockHandler = "flowRuleFailException")
    public String flowRuleConsoleDynamic(){
        log.info("动态创建sentinel>>>>");
        return "flowRuleConsoleDynamic-success";
    }

    /**
     * 不写注解
     * @return
     */
    @GetMapping("/flowRuleConsoleDynamic1")
    public String flowRuleConsoleDynamic1(){
        log.info("动态创建sentinel>>>>");
        return "flowRuleConsoleDynamic1-success";
    }

    /**
     * 信号量隔离(sentinel即阈值类型为线程数)
     * @return
     */
    @GetMapping("/flowRuleSemaphore")
    @SentinelResource(value = "flowRuleSemaphore",blockHandler = "flowRuleFailException")
    public String flowRuleSemaphore(){
        try {
            //加一个休眠状态以便能看出效果
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        log.info(Thread.currentThread().getName()+">>>>");
        return "flowRuleSemaphore-success";
    }

}
